package com.example.hxds.odr.service.Impl;

import cn.hutool.core.map.MapUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.codingapi.txlcn.tc.annotation.LcnTransaction;
import com.example.hxds.common.exception.HxdsException;
import com.example.hxds.common.util.PageUtils;
import com.example.hxds.odr.controller.form.TransferForm;
import com.example.hxds.odr.db.dao.OrderBillDao;
import com.example.hxds.odr.db.dao.OrderDao;
import com.example.hxds.odr.db.pojo.OrderBillEntity;
import com.example.hxds.odr.db.pojo.OrderEntity;
import com.example.hxds.odr.db.pojo.OrderProfitsharingEntity;
import com.example.hxds.odr.feign.DrServiceApi;
import com.example.hxds.odr.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.LocalTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Author XUYANG
 * @Date 2024-03-12 16:39
 */
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
    @Resource
    private OrderDao orderDao;
    @Resource
    private OrderBillDao billDao;
    @Resource
    private RedisTemplate redisTemplate;
    @Autowired
    private DrServiceApi drServiceApi;
    @Override
    public HashMap searchDriverTodayBusinessData(long driverId) {
        HashMap res=orderDao.searchDriverTodayBusinessData(driverId);
        return res;
    }

    @Override
    @Transactional
    @LcnTransaction
    public String insertOrder(OrderBillEntity billEntity, OrderEntity orderEntity) {
        int rows=orderDao.insert(orderEntity);
        if (rows==1){
            String id=orderDao.searchOrderIdByUUID(orderEntity.getUuid());
            billEntity.setOrderId(Long.parseLong(id));
            rows=billDao.insert(billEntity);
            if (rows==1){
                redisTemplate.opsForValue().set("order#"+id,"none");
                redisTemplate.expire("order#"+id,16, TimeUnit.MINUTES);
                return id;
            }else {
                throw new HxdsException("保存订单费用失败");
            }
        }else {
            throw new HxdsException("保存新订单失败");
        }
    }

    @Override
    @Transactional
    @LcnTransaction
    public String acceptNewOrder(long driverId, long orderId) {
        if (!redisTemplate.hasKey("order#"+orderId)){
            return "抢单失败";
        }
        redisTemplate.execute(new SessionCallback() {
            @Override
            public Object execute(RedisOperations operations) throws DataAccessException {
                //获取新订单记录的Version
                operations.watch("order#"+orderId);
                //本地缓存Redis操作
                operations.multi();
                //把新订单缓存的Value设置成抢单司机的ID
                operations.opsForValue().set("order#"+orderId,driverId);

                return operations.exec();
            }
        });
        //抢单成功后，删除Redis中的新订单，避免让其他司机参与抢单
        redisTemplate.delete("order#"+orderId);
        //更新订单记录，添加上结丹司机的ID和接单时间
        HashMap param=new HashMap(){{
            put("driverId",driverId);
            put("orderId",orderId);
        }};
        int rows=orderDao.acceptNewOrder(param);
        if (rows!=1){
            throw new HxdsException("抢单失败，无法更新订单记录");
        }

        return "接单成功";
    }

    @Override
    public Integer searchOrderStatus(Map param) {
        Integer status=orderDao.searchOrderStatus(param);
        if (status==null){
//            throw new HxdsException("没有查询到数据，请核对查询条件");
            status=0;
        }
        return status;
    }

    @Override
    @Transactional
    @LcnTransaction
    public String deleteUnAcceptOrder(Map param) {
        long orderId= MapUtil.getLong(param,"orderId");
        if (!redisTemplate.hasKey("order#"+orderId)){
            return "未从缓存中查询到该订单，取消失败";
        }
        redisTemplate.execute(new SessionCallback() {
            @Override
            public Object execute(RedisOperations operations) throws DataAccessException {
                operations.watch("order#"+orderId);
                operations.multi();
                operations.opsForValue().set("order#"+orderId,"none");
                return operations.exec();
            }
        });
        redisTemplate.delete("order#"+orderId);
        int rows=orderDao.deleteUnAcceptOrder(param);
        if (rows!=1){
            return "订单取消失败";
        }
        rows=billDao.deleteUnAcceptOrderBill(orderId);
        if (rows!=1){
            return "账单取消失败";
        }
        return "订单取消成功";
    }

    @Override
    public HashMap searchDriverCurrentOrder(long driverId) {
        HashMap res=orderDao.searchDriverCurrentOrder(driverId);
        return res;
    }

    @Override
    public HashMap hasCustomerCurrentOrder(long customerId) {
        HashMap result=new HashMap();
        HashMap map=orderDao.hasCustomerUnAcceptOrder(customerId);
        result.put("hasCustomerUnAcceptOrder",map!=null);
        result.put("unAcceptOrder",map);
        Long id=orderDao.hasCustomerUnFinishedOrder(customerId);
        result.put("hasCustomerUnFinishedOrder",id!=null);
        result.put("unFinishedOrder",id);
        return result;
    }

    @Override
    public HashMap searchOrderForMoveById(Map param) {
        HashMap res=orderDao.searchOrderForMoveById(param);
        return res;
    }

    @Override
    @Transactional
    @LcnTransaction
    public int arriveStartPlace(Map param) {
        //到达上车标志位
        long orderId=MapUtil.getLong(param,"orderId");
        redisTemplate.opsForValue().set("order_driver_arrived#"+orderId,"1");
        int rows=orderDao.updateOrderStatus(param);
        if (rows!=1){
            throw new HxdsException("更新订单状态失败");
        }
        return rows;
    }

    @Override
    @Transactional
    @LcnTransaction
    public boolean confirmArriveStartPlace(long orderId) {
        String key="order_driver_arrived#"+orderId;
        if (redisTemplate.hasKey(key)&&redisTemplate.opsForValue().get(key).toString().endsWith("1")){
            redisTemplate.opsForValue().set(key,"2");
            return true;
        }
        return false;
    }

    @Override
    @Transactional
    @LcnTransaction
    public int startDriving(Map param) {
        long orderId=MapUtil.getLong(param,"orderId");
        String key="order_driver_arrived#"+orderId;
        boolean rightStatus=redisTemplate.hasKey(key);
        rightStatus=rightStatus&&redisTemplate.opsForValue().get(key).toString().endsWith("2");
        if (rightStatus){
            redisTemplate.delete(key);
            int rows=orderDao.updateOrderStatus(param);
            if (rows!=1){
                throw new HxdsException("更新订单状态失败");
            }
            return rows;
        }
        return 0;
    }

    @Override
    @Transactional
    @LcnTransaction
    public int updateOrderStatus(Map param) {
        int rows=orderDao.updateOrderStatus(param);
        if (rows!=1){
            throw new HxdsException("更新取消订单记录失败");
        }
        return rows;
    }

    @Override
    public PageUtils searchOrderByPage(Map param) {
        long count=orderDao.searchOrderCount(param);
        ArrayList<HashMap> list=null;
        if (count==0){
            list=new ArrayList<>();
        }else {
            list=orderDao.searchOrderByPage(param);
        }
        int start=MapUtil.getInt(param,"start");
        int length=MapUtil.getInt(param,"length");
        PageUtils pageUtils=new PageUtils(list,count,start,length);
        return pageUtils;
    }

    @Override
    public HashMap searchOrderContent(long orderId) {
        HashMap res=orderDao.searchOrderContent(orderId);
        JSONObject startPlaceLocation = JSONUtil.parseObj(MapUtil.getStr(res, "startPlaceLocation"));
        JSONObject endPlaceLocation = JSONUtil.parseObj(MapUtil.getStr(res, "endPlaceLocation"));
        res.replace("startPlaceLocation",startPlaceLocation);
        res.replace("endPlaceLocation",endPlaceLocation);
        return res;
    }

    @Override
    public ArrayList<HashMap> searchOrderStartLocationIn30Days() {
        ArrayList<String> list=orderDao.searchOrderStartLocationIn30Days();
        ArrayList<HashMap> res=new ArrayList<>();
        list.forEach(location->{
            JSONObject json=JSONUtil.parseObj(location);
            String latitude=json.getStr("latitude");
            String longitude=json.getStr("longitude");
            latitude=latitude.substring(0,latitude.length()-4);
            latitude+="0001";
            longitude=longitude.substring(0,longitude.length()-4);
            longitude+="0001";
            HashMap map=new HashMap<>();
            map.put("latitude",latitude);
            map.put("longitude",longitude);
            res.add(map);
        });
        return res;
    }

    @Override
    public boolean validDriverOwnOrder(Map param) {
        long count=orderDao.validDriverOwnOrder(param);
        return count==1?true:false;
    }

    @Override
    public HashMap searchSettlementNeedData(long orderId) {
        HashMap map=orderDao.searchSettlementNeedData(orderId);
        return map;
    }

    @Override
    public HashMap searchOrderById(Map param) {
        HashMap map=orderDao.searchOrderById(param);
        String startPlaceLocation=MapUtil.getStr(map,"startPlaceLocation");
        String endPlaceLocation=MapUtil.getStr(map,"endPlaceLocation");
        map.replace("startPlaceLocation",JSONUtil.parseObj(startPlaceLocation));
        map.replace("endPlaceLocation",JSONUtil.parseObj(endPlaceLocation));
        return map;
    }

    @Override
    public HashMap validCanPayOrder(Map param) {
        HashMap map=orderDao.validCanPayOrder(param);
        if (map==null||map.size()==0){
            throw new HxdsException("订单无法支付");
        }
        return map;
    }

    @Override
    @Transactional
    @LcnTransaction
    public int updateOrderPrepayId(Map param) {
        int rows=orderDao.updateOrderPrepayId(param);
        if (rows!=1){
            throw new HxdsException("更新预支付订单Id失败");
        }
        return rows;
    }

    @Override
    @Transactional
    @LcnTransaction
    public void handlePayment(String uuid, String payId, String driverOpenId, String payTime) {
        HashMap map=orderDao.searchOrderIdAndStatus(uuid);
        int status=MapUtil.getInt(map,"status");
        if (status==7){
            return;
        }
        HashMap param=new HashMap<>(){{
            put("uuid",uuid);
            put("payId",payId);
            put("payTime",payTime);
        }};
        int rows=orderDao.updateOrderPayIdAndStatus(param);
        if (rows!=1){
            throw new HxdsException("更新支付订单Id失败");
        }

        //查询系统奖励
        map=orderDao.searchDriverIdAndIncentiveFee(uuid);
        String incentiveFee=MapUtil.getStr(map,"incentiveFee");
        long driverId=MapUtil.getLong(map,"driverId");
        if (new BigDecimal(incentiveFee).compareTo(new BigDecimal("0.00"))==1){
            TransferForm form=new TransferForm();
            form.setUuid(uuid);
            form.setAmount(incentiveFee);
            form.setDriverId(driverId);
            form.setType((byte)2);
            form.setRemark("系统奖励费");

            drServiceApi.transfer(form);
        }
        //TODO 执行分账
    }

    @Override
    @Transactional
    @LcnTransaction
    public String updateOrderAboutPayment(Map param) {
        long orderId=MapUtil.getLong(param,"orderId");
        HashMap map=orderDao.searchUuidAndStatus(orderId);
        String uuid=MapUtil.getStr(map,"uuid");
        int status=MapUtil.getInt(map,"status");
        if (status==7||status==8){
            return "付款成功";
        }
        map.clear();
        LocalDateTime dateTime=LocalDateTime.now();
        DateTimeFormatter formatter=DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        String payTime=dateTime.format(formatter);
        param.put("payTime",payTime);
        int rows=orderDao.updateOrderAboutPayment(param);
        if (rows!=1){
            throw new HxdsException("更新的订单相关付款信息失败");
        }
        map=orderDao.searchDriverIdAndIncentiveFee(uuid);
        String incentiveFee=MapUtil.getStr(map,"incentiveFee");
        long driverId=MapUtil.getLong(map,"driverId");
        if (new BigDecimal(incentiveFee).compareTo(new BigDecimal("0.00"))==1){
            TransferForm form=new TransferForm();
            form.setUuid(uuid);
            form.setAmount(incentiveFee);
            form.setDriverId(driverId);
            form.setType((byte)2);
            form.setRemark("系统奖励费");

            drServiceApi.transfer(form);
        }
        return "付款成功";
    }

    @Override
    public PageUtils searchDriverOrderByPage(Map param) {
        long count=orderDao.searchDriverOrderCount(param);
        ArrayList<HashMap> list=null;
        if (count>0){
            list=orderDao.searchDriverOrderByPage(param);
        }else {
            list=new ArrayList<>();
        }
        int start=(Integer) param.get("start");
        int length=(Integer) param.get("length");
        PageUtils pageUtils=new PageUtils(list,count,start,length);
        return pageUtils;
    }

    @Override
    public PageUtils searchCustomerOrderByPage(Map param) {
        long count=orderDao.searchCustomerOrderCount(param);
        ArrayList<HashMap> list=null;
        if (count>0){
            list=orderDao.searchCustomerOrderByPage(param);
        }else {
            list=new ArrayList<>();
        }
        int start=(Integer) param.get("start");
        int length=(Integer) param.get("length");
        PageUtils pageUtils=new PageUtils(list,count,start,length);
        return pageUtils;
    }

    @Override
    public String searchCommentIdByOrderId(long orderId) {
        String commentId=orderDao.searchCommentIdByOrderId(orderId);
        return commentId;
    }


    @Override
    public HashMap searchDriverExecuteOrder(Map param){
        HashMap map=orderDao.searchDriverExecuteOrder(param);
        return map;
    }
}
